/**
 * @brief 单例模式。分别使用两种方式实现单例模式，传统的互斥锁方式和meyer'方式。
 * @version 1.3
 * @author 宋炜
 * @date 2023-03-08 ~ 2025-8-12
 *   2024-12-13 增加了多线程支持
 *   2025-8-12 改用uncopyable用来限制拷贝；修改了其他的一些小问题
 *   2025-8-12 增加了meyer's单例实现方法
 *   2025-8-12 增加动态库的支持
 */

#pragma once

#include <memory>
#include <type_traits>
#include <mutex>
#include <atomic>

#include "uncopyable.hpp"

/// 在默认情况下考虑选择meyer's方式
#if !defined( MEYER_S )
#    define   MEYER_S    (1)
#endif

/// 单例模式在跨动态库的情况下, 静态变量可能会失效。通过控制导出符号的的方式来解决这个问题
/// 在默认的情况下不打开动态库兼容开关。
#if !defined( SINGLETON_EXPORTS )
#    define SINGLETON_EXPORTS   (0)
#endif

#if defined( _MSC_VER )
#    if SINGLETON_EXPORTS == 1
#        define DLL_API __declspec(dllexport)
#    else
#        define DLL_API __declspec(dllimport)
#    endif
#elif defined( __GNUC__ ) || defined( __clang__ ) || defined( __linux__ )
#    if SINGLETON_EXPORTS == 1
#        define DLL_API __attribute__((visibility("default")))
#    else
#        define DLL_API 
#    endif
#endif

namespace wheels
{
    namespace dm
    {
#if MEYER_S == 1
    template <typename typeName >
    class DLL_API singleton : private uncopyable {
    public:
        using type = typename std::remove_pointer< typename std::decay<typeName >::type >::type;
        static_assert( std::is_class< type >::value , "" );
    protected:
        /***
        * @brief 获取单例对象的引用（线程安全）
        * @tparam Args 构造参数类型
        * @return 单例对象的指针的指针
        */
        static type** instance() {
            static type * inst = nullptr; 
            return &inst;
        }
    public:
        /**
         * @brief 创建并获取单例对象的指针
         * @tparam Args 构造参数类型
         * @param args 传递给构造函数的参数
         * @return 单例对象的指针
         * @note 接口保持兼容性，实际行为与 instance() 相同
         */
        template< typename ...Args >
        static type* create( Args&&... args ) {
            static std::once_flag flag;  // 确保初始化仅执行一次
            type** inst = instance();
            
            std::call_once(flag, [&]() {
                *inst = new type(std::forward<Args>(args)...);
                // 注册销毁函数，程序退出时自动释放
                static std::unique_ptr<type> deleter( *inst );
            });
            
            return * inst;
        }
        /**
         * @brief 创建并获取单例对象的指针
         * @tparam Args 构造参数类型
         * @param args 传递给构造函数的参数
         * @return 单例对象的指针
         * @note 接口保持兼容性，实际行为与 instance() 相同
         */
        template< typename ...Args >
        static std::shared_ptr< type > create_shared( Args&&... args ){
            type * p = create( std::forward< Args >( args )... );
            return std::shared_ptr< type >( p , []( type *){} );
        }
        /**
         * @brief 获取单例对象的指针（无参版本）
         * @return 单例对象的指针
         * @note 要求单例类型必须有默认构造函数
         *       等价于调用 instance()
         */
        static type* get() {
            return *instance();
        }
        
        // 获取单例实例（共享指针）
        static std::shared_ptr<type> get_shared() {
            auto instance_ptr = std::shared_ptr< type >( get() , [](type*){});
            return instance_ptr;
        }
    };
#else
    template< typename typeName >
    class DLL_API singleton : public uncopyable
    {
    public:
        using type = typename std::remove_pointer< typename std::decay<typeName >::type >::type;
        static_assert( std::is_class< type >::value , "目标必须是一个类" );
    protected:
        static std::mutex                  m_mutex__;
        static std::shared_ptr< type >     pt_obj__;
    public:
        /**
         * @brief 创建并获取单例对象的指针（线程安全）
         * @tparam Args 构造参数类型
         * @param args 传递给构造函数的参数
         * @return 单例对象的指针，如果已存在则返回现有对象
         * @note 首次调用时创建单例对象，后续调用返回同一对象
         *        如果内存分配失败或构造函数抛出异常，返回空指针
         */
        template< typename ...Args >
        static type * create( Args&&... args ){
            std::lock_guard< std::mutex >   LCK( m_mutex__ );
            if( pt_obj__ ) return pt_obj__.get();
                
            pt_obj__ = std::make_shared< type >( std::forward< Args >(args)...);
            
            type * ret = pt_obj__.get();
            
            return ret;
        }
        /**
         * @brief手动强制释放对象
         */
        static void reset(){
            std::lock_guard< std::mutex > LCK( m_mutex__ );
            if( pt_obj__ ){
                pt_obj__.reset();
            }
        }
        /**
         * @brief 创建并获取单例对象的指针（线程安全）
         * @tparam Args 构造参数类型
         * @param args 传递给构造函数的参数
         * @return 单例对象的指针，如果已存在则返回现有对象
         * @note 首次调用时创建单例对象，后续调用返回同一对象
         *        如果内存分配失败或构造函数抛出异常，返回空指针
         */
        template< typename ...Args >
        static std::shared_ptr< type > create_shared( Args&&... args ){
            std::lock_guard< std::mutex >   LCK( m_mutex__ );
            if( pt_obj__ ){
                std::weak_ptr< type > tmp( pt_obj__ );
                if( tmp.expired() == false ){
                    return tmp.lock();
                }
                return {};
            }
                
            pt_obj__= std::make_shared< type >( std::forward< Args >(args)...);
            
            return pt_obj__;
        }

        /**
         * @brief 获取当前的模块对象指针
         * @return 返回指针，如果模块没有初始化返回时nullptr
         */
        static type * get(){
			std::lock_guard< std::mutex > LCK( m_mutex__ );
            return pt_obj__.get();
        }
        /**
         * @brief 获取shared_ptr方式的对象指针
         * @return 如果单例指针有效返回对象指针。否则返回空的nullptr
         */
        static std::shared_ptr< type > get_shared()
        { 
            std::lock_guard< std::mutex > LCK( m_mutex__ );
            
            return pt_obj__;
        }
    };

    #define IMP_SINGLETON( type )   \
        template<> std::shared_ptr< type > singleton< type > :: pt_obj__ = {};\
        template<> std::mutex singleton< type > :: m_mutex__ = {}
    #endif
    }
}

